#ifndef GUI_H_INCLUDED
#define GUI_H_INCLUDED

#include "Common.h"

enum GUI_SLOT {
    GCONSOLE = 0,
    GCTRLPANEL = 1,
    GOBJTIPS = 2,
    GINVENTORY = 3,
    GSELLLIST = 4,
    GMAX,
};

enum GUI_CONST {
    GT_CONSOLE_FLICKTIME = 20,
    GT_CONSOLE_MAXLINE =  9,
    GT_CONSOLE_MAXINPUT = 80,
    GT_CONSOLE_TRANSPARENT_ALPHA = 180,
};

enum GUI_EVENT_TYPE {
    ET_NONE,
    ET_CHAR,
    ET_MOUSE_LEFT,
    ET_MOUSE_MIDDLE,
    ET_MOUSE_RIGHT,

    ET_SHOW,
    ET_HIDE,
    ET_ISSHOW,
    ET_REVERSE_SHOW_HIDE,

    ET_NONE_TIPS,
    ET_MONSTER_TIPS,
    ET_ITEM_TIPS,

    ET_BIND_SELL,

    ET_MAX,
};

#define PROMPT "[shell]$"

struct GuiEvent {
    GuiEvent() : m_type(ET_NONE) {}
    short m_type;
    int   m_char;
    short   m_x;
    short   m_y;
    void *m_data;
};


class GuiBase {
public:
    GuiBase() : m_show(false) {}
    GuiBase(const Rect &rect) : m_show(false), m_position(rect) {}
    virtual ~GuiBase(){}

    inline bool   isshow() const { return m_show; }
    inline void   show(bool flag) { m_show = flag; }
    inline void   setPos(ushort x, ushort y) { m_position.x = x; m_position.y = y;}
    inline void   setSize(ushort w, ushort h) { m_position.w = w; m_position.h = h;}
    inline const  Rect &position() const { return m_position; }

    virtual bool  process_event(const GuiEvent &event) { return false; }
    virtual void  draw(BITMAP *surface) = 0;

protected:
    bool m_show;
    Rect m_position;
};

class GuiManager {
public:
    GuiManager();
    ~GuiManager();
    bool GuiObjCommand(GUI_SLOT slot, const GuiEvent &arg);
    void Draw(BITMAP *surface);

private:
    GuiBase *m_guis[GMAX];
};

class GuiConsole : public GuiBase {
public:
    GuiConsole(const Rect &rect);

    virtual bool  process_event(const GuiEvent &event);
    virtual void  draw(BITMAP *surface);
    void printline(const char *msg);
    void printline(const string &msg);
    void showhistory();
    void clear();

private:
    void addcmdhistory(const char *cmd);
    const string &nextcmd();
    const string &prevcmd();
    const string &matchcmd(const char *cmd, int len);

    short m_flicker;
    char  m_step;
    uchar m_promptlen;
    uchar m_caret;
    char  m_text[GT_CONSOLE_MAXINPUT];
    uchar m_hisindex;
    char  m_history[GT_CONSOLE_MAXLINE][GT_CONSOLE_MAXINPUT];
    ushort m_cmdidx;
    string m_null;
    vector<string> m_cmdhistory;
};

class Item;

class ObjectTips : public GuiBase {
public:
    enum OBJECT_TYPE {
        OBJ_NONE,
        OBJ_MONSTER,
	OBJ_ITEM,
    };

    ObjectTips(const Rect &rect) : GuiBase(rect), m_type(OBJ_NONE) {}
    void draw(BITMAP *surface);
    virtual bool  process_event(const GuiEvent &event);
    void setNone() { m_type = OBJ_NONE; }

private:
    OBJECT_TYPE m_type;
    int         m_offset;
    int         m_id;
    Item       *m_item;
};

typedef void (*pEventFun) (GuiBase *which, const GuiEvent *);

class GuiButton : public GuiBase {
public:
    GuiButton();
    void setTile(BITMAP *tile);
    void setAction(pEventFun);
    void draw(BITMAP *surface);
    virtual bool  process_event(const GuiEvent &event) ;
    inline const Rect &position() const { return m_position; }

private:
    pEventFun m_process;
    BITMAP   *m_tile;
};

class GuiCtrlPanel : public GuiBase {
public:
    GuiCtrlPanel(const Rect &pos);
    ~GuiCtrlPanel();
    void addButton(GuiButton *button);
    void draw(BITMAP *surface);
    virtual bool  process_event(const GuiEvent &event) ;

private:
    BITMAP             *m_tile;
    vector<GuiButton *> m_buttons;
};

class GInventory : public GuiBase {
public:
    GInventory (const Rect &rect);

    virtual bool  process_event(const GuiEvent &event);
    virtual void  draw(BITMAP *surface);
};

class GSellList : public GuiBase {
public:
    enum { SELL_W = 4, SELL_H = 3, SELL_WH = SELL_W*SELL_H };
    GSellList (const Rect &rect);

    virtual bool  process_event(const GuiEvent &event);
    virtual void  draw(BITMAP *surface);

private:
    int  m_page;
    Rect m_next;
    Rect m_prev;
    vector<Item *> *m_sell_list;
};

#endif // GUI_H_INCLUDED
